package com.itheima.reggie.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.common.CustomException;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.mapper.DishMapper;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.DishFlavorService;
import com.itheima.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author DL5O
 * @version 1.0
 */
@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
    @Autowired
    DishFlavorService dishFlavorService;

    @Autowired
    CategoryService categoryService;

    @Override
    public Page<DishDto> getPage(Integer page, Integer pageSize, String name) {
        //1.构造分页构造器对象
        Page<Dish> dishPage = new Page<>(page, pageSize);
        Page<DishDto> dishDtoPage = new Page<>();

        //2.条件构造器
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();
        qw.like(StringUtils.isNotEmpty(name), Dish::getName, name);
        qw.orderByDesc(Dish::getUpdateTime);

        //执行分页
        super.page(dishPage, qw);

        //对象拷贝,忽略records
        BeanUtils.copyProperties(dishPage, dishDtoPage, "records");

        //处理records集合
        List<Dish> records = dishPage.getRecords();
        List<DishDto> list = records.stream().map((item) -> {
            DishDto dishDto = new DishDto();
            //1.把item中的属性拷贝到disDto中去
            BeanUtils.copyProperties(item, dishDto);

            Long categoryId = item.getCategoryId();//获得每个菜品分类id

            //2.根据id获取分类对象
            Category category = categoryService.getById(categoryId);//分类对象
            if (category != null) {
                String categoryName = category.getName();//获得分类名称
                //3.设置分类名到dishDto中
                dishDto.setCategoryName(categoryName);
            }
            return dishDto;
        }).collect(Collectors.toList());//把dishDto对象收集起来，并转成list集合

        dishDtoPage.setRecords(list);//把record设置回去
        return dishDtoPage;
    }

    @Override
    public List<DishDto> getList(Dish dish) {
        //1.编写查询的对应sql
        //sql：select * from dish where categoryId = #{categoryId} and name like '%辣%' and status = 1
        LambdaQueryWrapper<Dish> qw = new LambdaQueryWrapper<>();

        //2.设置条件
        qw.eq(dish.getCategoryId()!= null,Dish::getCategoryId, dish.getCategoryId());
        qw.like(StringUtils.isNotEmpty(dish.getName()), Dish::getName, dish.getName());
        qw.eq(dish.getStatus()!=null,Dish::getStatus,dish.getStatus());

        //3.调用service层查询查询即可
        List<Dish> list = super.list(qw);

        //4.根据菜品id去查询相应的口味信息
        List<DishDto> listDtoList = list.stream().map((item)->{
            DishDto dishDto = new DishDto();

            //5.进行值拷贝
            BeanUtils.copyProperties(item,dishDto);

            //6.取出菜品id，查询对应的口味信息
            LambdaQueryWrapper<DishFlavor> dishFlavorQW = new LambdaQueryWrapper<>();
            dishFlavorQW.eq(DishFlavor::getDishId,item.getId());
            List<DishFlavor> dishFlavorList = dishFlavorService.list(dishFlavorQW);

            //7.进行设置
            dishDto.setFlavors(dishFlavorList);

            return dishDto;
        }).collect(Collectors.toList());
        return listDtoList;
    }

    /**
     * 新增菜品，同时保存对应的口味数据
     *
     * @param dishDto
     */
    @Override
    @Transactional//加入事务控制保证数据的一致性
    public void saveWithFlavor(DishDto dishDto) {
        //1.保存菜品的基本信息到菜品dish
        boolean saveDish = this.save(dishDto);

        if (dishDto.getFlavors() == null) {
            return;
        }
        //保存基本信息到菜品表,在插入之间mp会帮我们补全id，并放到dishDto这个对象中
        Long dishId = dishDto.getId();//菜品的id

        //2.保存菜品口味数据到菜品口味表dish_flavor
        List<DishFlavor> flavors = dishDto.getFlavors();

        //3.使用stream流来进行编程
        flavors.stream().map((item) -> {
            item.setDishId(dishId);
            return item;
        }).collect(Collectors.toList());
        dishFlavorService.saveBatch(flavors);
    }

    /**
     * 编辑菜品
     *
     * @param dishDto
     */
    @Override
    @Transactional
    public void updateWithFlavor(DishDto dishDto) {
        //1.更新dish表中的数据
        this.updateById(dishDto);

        //2.更新dish_flavor表中的数据
        //分为两步：清理当前菜品对应的口味信息，添加当前提交过来的口味数据
        if (dishDto.getFlavors() == null) {
            return;
        }
        //2.1清理当前菜品对应的口味信息
        LambdaQueryWrapper<DishFlavor> qw = new LambdaQueryWrapper<>();
        qw.eq(DishFlavor::getDishId, dishDto.getId());
        dishFlavorService.remove(qw);

        //2.2添加当前提交过来的口味数据
        List<DishFlavor> flavors = dishDto.getFlavors();
        flavors.stream().map((item) -> {
            item.setDishId(dishDto.getId());
            return item;
        }).collect(Collectors.toList());

        dishFlavorService.saveBatch(flavors);
        
    }

    /**
     * 获得dishDto对象，用于修改菜品信息时数据的回显
     *
     * @param id 菜品的id
     * @return
     */
    @Override
    @Transactional
    public DishDto getDishDtoById(Long id) {
        DishDto dishDto = new DishDto();

        //1.根据id查询菜品信息，并将菜品的属性拷贝到dishDto中去
        Dish dish = this.getById(id);
        BeanUtils.copyProperties(dish, dishDto);

        //2.根据菜品id查询对应的口味，是一个list
        LambdaQueryWrapper<DishFlavor> qw = new LambdaQueryWrapper<>();
        qw.eq(DishFlavor::getDishId, id);
        List<DishFlavor> flavorsList = dishFlavorService.list(qw);

        //3.将查出来的口味list赋给dishDto
        dishDto.setFlavors(flavorsList);
        return dishDto;
    }

    @Override
    public void updateStatus(Integer status, List<Long> ids) {
        //1.按照ids进行查询，返回一个list 集合
        List<Dish> dishes = this.listByIds(ids);

        //2.取出集合中的每个元素，对status进行修改
        dishes.stream().map((item) -> {
            item.setStatus(status);
            return item;
        }).collect(Collectors.toList());

        //3.按集合保存集合
        this.updateBatchById(dishes);
    }

    /**
     * 删除/批量删除
     * @param ids
     */
    @Override
    @Transactional
    public void removeWithFlavor(List<Long> ids) {

        //1.统计id在ids中，且是起售状态的记录条数
        //select count(*) from dish where id in (ids) and status = 1
        LambdaQueryWrapper<Dish> dishQueryWrapper = new LambdaQueryWrapper<>();
        dishQueryWrapper.in(Dish::getId, ids);
        dishQueryWrapper.eq(Dish::getStatus, 1);

        //2.如果查出来的记录条数大于0，就不进行删除，并抛出异常
        int count = this.count(dishQueryWrapper);
        if (count > 0) {
            //就抛出异常
            throw new CustomException("该菜品起售中，无法删除，需停售后再删除");
        }

        //3.如果可以删除，先删除口味表（dish_flavor）中的 dish_id = id的记录
        //delete from dish_flavor where dish_id in (ids)
        LambdaQueryWrapper<DishFlavor> dishFlavorQueryWrapper = new LambdaQueryWrapper<>();
        dishFlavorQueryWrapper.in(DishFlavor::getDishId,ids);
        dishFlavorService.remove(dishFlavorQueryWrapper);

        //4.删除dish中的记录
        this.removeByIds(ids);
    }


}
